/**
 * Copyright (C) 2010 Cloudfarming <info@cloudfarming.nl>
 *
 * Licensed under the Eclipse Public License - v 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.eclipse.org/legal/epl-v10.html
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.cloudfarming.client.geoviewer.jxmap.map;

import java.awt.Component;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import javax.swing.JComponent;
import org.netbeans.api.visual.widget.Scene;
import org.netbeans.api.visual.widget.Widget;

/**
 * Forwards events from the Scene to the specified component. So we can have the
 * widgets layer on top of the map (because of the interaction with the widgets)
 * and sends mouse events from here to the layered pane. On this way we can 
 * for example zoom in and out, and also use the tooltip functionality on a 
 * widget.
 * 
 * @author Timon Veenstra
 */
public final class MouseEventForwarder implements MouseListener, MouseMotionListener, MouseWheelListener {

    private final Scene scene;
    private final Component component;

    public MouseEventForwarder(final Scene scene, final Component component) {
        this.scene = scene;
        this.component = component;
    }

    /**
     * Forwards the mouse event when it's not effected a widget.
     * 
     * @param event The event to forward
     */
    private void forwardEvent(final MouseEvent event) {
        if (!isHit(scene.convertViewToScene(event.getPoint()), scene)) {
            if (component instanceof JComponent) {
                for (final Component child : ((JComponent) component).getComponents()) {
                    child.dispatchEvent(event);
                }
            }
        }
        component.dispatchEvent(event);
    }

    /**
     * Returns true when the event occured on a widget.
     * 
     * @param point Point from where the event was occured
     * @param widget Widget to check
     * @return
     */
    private boolean isHit(final Point point, final Widget widget) {
        for (final Widget child : widget.getChildren()) {
            if (isHit(point, child)) {
                return true;
            }
        }

        if (!(widget instanceof Scene) && widget.isHitAt(widget.convertSceneToLocal(point))) {
            return true;
        }

        return false;
    }

    @Override
    public void mouseClicked(MouseEvent event) {
        forwardEvent(event);
    }

    @Override
    public void mousePressed(MouseEvent event) {
        forwardEvent(event);
    }

    @Override
    public void mouseReleased(MouseEvent event) {
        forwardEvent(event);
    }

    @Override
    public void mouseEntered(MouseEvent event) {
        forwardEvent(event);
    }

    @Override
    public void mouseExited(MouseEvent event) {
        forwardEvent(event);
    }

    @Override
    public void mouseDragged(MouseEvent event) {
        forwardEvent(event);
    }

    @Override
    public void mouseMoved(MouseEvent event) {
        forwardEvent(event);
    }

    @Override
    public void mouseWheelMoved(MouseWheelEvent event) {
        forwardEvent(event);
    }
}
